import os
import random

from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext.webapp import template

from model import Game, Player, Dice, Score, Language

from tools import manager

class YamsManager(manager.Manager):
    """
    """

    def new_game(self, game_name):
        """
        """
        game_name = game_name.strip()
        if game_name == '':
            game_name = ' '

        game_query = Game().all()
        game_query.filter('name =', game_name)

        if game_query.count() > 0:
            return None

        #
        game = Game()
        game.name = game_name
        #
        game.put()

        return game

    def new_player(self, player_name):
        """
        """
        player_name = player_name.strip()
        if player_name == '':
            player_name = ' '

        player_query = Player().all()
        player_query.filter('name =', player_name)
        player_query.order('name')

        if player_query.count() > 0:
            return None

        #
        player = Player()
        player.name = player_name
        #
        player.put()

        return player.key()

    def player(self):
        """
        """
        # set the template for edit
        self.template_values['players'] = Player().all()
        self.template_values['games'] = Game().all()

        # find the template
        path = os.path.join(os.path.dirname(__file__),
                                '../templates', 'yams', 'player.html')

        # display the contact
        return template.render(path, self.template_values)

    def delete_player(self, player_key):
        """
        """
        player = Player().get(player_key)

        try:
            player.score.delete()
        except:
            pass

        # dice deletion
        dice_query = Dice().all()
        dice_query.filter('player =', player)
        for dice in dice_query:
            dice.delete()

        player.delete()

    def init_score(self, player_key):
        """
        """
        #
        player = Player().get(player_key)

        #
        score = Score()
        #
        score.one = -1
        score.two = -1
        score.three = -1
        score.four = -1
        score.five = -1
        score.six = -1
        #
        score.three_of_kind = -1
        score.four_of_kind = -1
        score.full = -1
        score.small_suite = -1
        score.big_suite = -1
        score.lucky = -1
        score.yams = -1
        #
        score.put()

        #
        player.score = score
        #
        player.put()

    def __init_dice(self, player, dice_name):
        """
        """
        query = Dice().all()
        query.filter('player =', player)
        query.filter('name =', dice_name)

        if query.count() > 0:
            for dice in query:
                dice.delete()

        dice = Dice()
        dice.player = player
        dice.name = dice_name
        dice.turn = 1
        dice.selected = False
        dice.value = random.randint(1, 6)
        dice.put()

    def init_dices(self, player_key):
        """
        """
        player = Player().get(player_key)

        self.__init_dice(player, 'dice1')
        self.__init_dice(player, 'dice2')
        self.__init_dice(player, 'dice3')
        self.__init_dice(player, 'dice4')
        self.__init_dice(player, 'dice5')

    def create_game(self, player_key):
        """
        """
        # set the template for edit
        self.template_values['player_key'] = player_key
        self.template_values['games'] = Game().all()

        # find the template
        path = os.path.join(os.path.dirname(__file__),
                                '../templates', 'yams', 'create_game.html')

        # display the contact
        return template.render(path, self.template_values)

    def create(self, player_key, game_name):
        """
        """
        #
        game = self.new_game(game_name)
        if game:
            #
            player = Player().get(player_key)
            player.game = game
            player.put()
            return True

        # game wasn't created
        return False

    def choose(self, player_key, game_key):
        """
        """
        #
        game = Game().get(game_key)
        #
        player = Player().get(player_key)
        player.game = game
        player.put()

    def choose_game(self, player_key):
        """
        """
        #
        player = Player().get(player_key)

        # set the template for edit
        self.template_values['player'] = player
        self.template_values['games'] = Game().all()

        # find the template
        path = os.path.join(os.path.dirname(__file__),
                                '../templates', 'yams', 'choose_game.html')

        # display the contact
        return template.render(path, self.template_values)

    def delete_game(self, game_key):
        """
        """
        # get the game to delete
        game = Game().get(game_key)

        # find the players
        player_query = Player().all()
        player_query.filter('game =', game)
        player_query.order('name')
        for player in player_query:
            # score delete
            player.score.delete()

            # dice deletion
            dice_query = Dice().all()
            dice_query.filter('player =', player)
            for dice in dice_query:
                dice.delete()

            # delete the current player
            player.delete()

        # delete the expected game
        game.delete()


    def roll(self, player_key, dice1,
            dice2, dice3, dice4, dice5):
        """
        """
        player = Player().get(player_key)

        # value to return
        new_turn = True

        #
        query = Dice().all()
        query.filter('name =', 'dice1')
        query.filter('player =', player)
        d1 = query.get()
        if d1.turn > 2:
            return False

        #
        query = Dice().all()
        query.filter('name =', 'dice2')
        query.filter('player =', player)
        d2 = query.get()
        if d2.turn > 2:
            return False

        #
        query = Dice().all()
        query.filter('name =', 'dice3')
        query.filter('player =', player)
        d3 = query.get()
        if d3.turn > 2:
            return False

        #
        query = Dice().all()
        query.filter('name =', 'dice4')
        query.filter('player =', player)
        d4 = query.get()
        if d4.turn > 2:
            return False

        #
        query = Dice().all()
        query.filter('name =', 'dice5')
        query.filter('player =', player)
        d5 = query.get()
        if d5.turn > 2:
            return False

        if not dice1 == '':
            turn = d1.turn + 1
            d1.turn = turn
            if turn > 2:
                d1.put()
                new_turn = False
            d1.value = random.randint(1, 6)
            d1.selected = False
        d1.put()

        if not dice2 == '':
            turn = d2.turn + 1
            d2.turn = turn
            if turn > 2:
                d2.put()
                new_turn = False
            d2.value = random.randint(1, 6)
            d2.selected = False
        d2.put()

        if not dice3 == '':
            turn = d3.turn + 1
            d3.turn = turn
            if turn > 2:
                d3.put()
                new_turn = False
            d3.value = random.randint(1, 6)
            d3.selected = False
        d3.put()

        if not dice4 == '':
            turn = d4.turn + 1
            d4.turn = turn
            if turn > 2:
                d4.put()
                new_turn = False
            d4.value = random.randint(1, 6)
            d4.selected = False
        d4.put()

        if not dice5 == '':
            turn = d5.turn + 1
            d5.turn = turn
            if turn > 2:
                d5.put()
                new_turn = False
            d5.value = random.randint(1, 6)
            d5.selected = False
        d5.put()

        return new_turn

    def get_number_item(self, name, value, dice1,
            dice2, dice3, dice4, dice5):
        """
        """
        score = 0
        if dice1 == value:
            score += value

        if dice2 == value:
            score += value

        if dice3 == value:
            score += value

        if dice4 == value:
            score += value

        if dice5 == value:
            score += value

        return {
                'name': name,
                'value': score,
                'new': score > 0,
                'cancel': score == 0
                }

    def one(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            return self.get_number_item('one', 1,
                    dice1, dice2, dice3, dice4, dice5)

        else:
            return {
                    'name': 'one',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def two(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            return self.get_number_item('two', 2,
                    dice1, dice2, dice3, dice4, dice5)

        else:
            return {
                    'name': 'two',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def three(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            return self.get_number_item('three', 3,
                    dice1, dice2, dice3, dice4, dice5)
        else:
            return {
                    'name': 'three',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def four(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            return self.get_number_item('four', 4,
                    dice1, dice2, dice3, dice4, dice5)

        else:
            return {
                    'name': 'four',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def five(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            return self.get_number_item('five', 5,
                    dice1, dice2, dice3, dice4, dice5)

        else:
            return {
                    'name': 'five',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def six(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            return self.get_number_item('six', 6,
                    dice1, dice2, dice3, dice4, dice5)

        else:
            return {
                    'name': 'six',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def same_of_kind(self, number_of_kind,
            dice1, dice2, dice3, dice4, dice5,
            different=None):
        """
        """
        found = dict()

        if not different == dice1:
            found[dice1] = 1

        if not different == dice2:
            if dice2 in found:
                nb = found[dice2]
                found[dice2] = nb + 1
            else:
                found[dice2] = 1

        if not different == dice3:
            if dice3 in found:
                nb = found[dice3]
                found[dice3] = nb + 1
            else:
                found[dice3] = 1

        if not different == dice4:
            if dice4 in found:
                nb = found[dice4]
                found[dice4] = nb + 1
            else:
                found[dice4] = 1

        if not different == dice5:
            if dice5 in found:
                nb = found[dice5]
                found[dice5] = nb + 1
            else:
                found[dice5] = 1

        for key in found.keys():
            if found[key] >= number_of_kind:
                return key

        return 0


    def three_of_kind(self, score, dice1, dice2, dice3, dice4, dice5):
        """
        """
        if score == -1:
            score = 0
            if self.same_of_kind(3, dice1, dice2, dice3, dice4, dice5):
                score = 50

            return {
                    'name': '3_of_kind',
                    'value': score,
                    'new': score > 0,
                    'cancel': score == 0
                    }

        else:
            return {
                    'name': '3_of_kind',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def four_of_kind(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            score = 0
            if self.same_of_kind(4, dice1, dice2, dice3, dice4, dice5):
                score = 75

            return {
                    'name': '4_of_kind',
                    'value': score,
                    'new': score > 0,
                    'cancel': score == 0
                    }

        else:
            return {
                    'name': '4_of_kind',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def full(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            score = 0
            different = self.same_of_kind(2, dice1, dice2,
                    dice3, dice4, dice5)
            if  self.same_of_kind(3, dice1, dice2,
                    dice3, dice4, dice5, different):
                score = 75

            return {
                    'name': 'full',
                    'value': score,
                    'new': score > 0,
                    'cancel': score == 0
                    }

        else:
            return {
                    'name': 'full',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def check_suite(self, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        # sorting
        sorted_dices = [dice1]
        if not dice2 in sorted_dices:
            sorted_dices.append(dice2)
        if not dice3 in sorted_dices:
            sorted_dices.append(dice3)
        if not dice4 in sorted_dices:
            sorted_dices.append(dice4)
        if not dice5 in sorted_dices:
            sorted_dices.append(dice5)

        for i in range(len(sorted_dices)):
            for j in range(len(sorted_dices)):
                if sorted_dices[i] < sorted_dices[j]:
                    temp = sorted_dices[i]
                    sorted_dices[i] = sorted_dices[j]
                    sorted_dices[j] = temp

        # avoid double
        sorted_dices_only = list()
        for d in sorted_dices:
            if not d in sorted_dices_only:
                sorted_dices_only.append(d)

        fail = 5
        if len(sorted_dices_only) == 5:
            dif = sorted_dices_only[4] - sorted_dices_only[0]
            if dif == 4:
                fail = 0

            dif1 = sorted_dices_only[4] - sorted_dices_only[1]
            dif2 = sorted_dices_only[3] - sorted_dices_only[0]
            if dif1 == 3 or dif2 == 3:
                fail = 1

        if len(sorted_dices_only) == 4:
            dif = sorted_dices_only[3] - sorted_dices_only[0]
            if dif == 3:
                fail = 1

        return fail

    def small_suite(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            score = 0
            fail = self.check_suite(dice1, dice2, dice3, dice4, dice5)
            if fail < 2:
                score = 50

            return {
                    'name': 's_suite',
                    'value': score,
                    'new': fail < 2,
                    'cancel': fail > 1
                    }

        else:
            return {
                    'name': 's_suite',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def big_suite(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            score = 0
            fail = self.check_suite(dice1, dice2, dice3, dice4, dice5)
            if fail == 0:
                score = 75

            return {
                    'name': 'b_suite',
                    'value': score,
                    'new': fail == 0,
                    'cancel': fail > 0
                    }

        else:
            return {
                    'name': 'b_suite',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def lucky(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            score = dice1
            score += dice2
            score += dice3
            score += dice4
            score += dice5
            return {
                    'name': 'lucky',
                    'value': score,
                    'new': True,
                    'cancel': False
                    }

        else:
            return {
                    'name': 'lucky',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def yams(self, score, dice1, dice2,
            dice3, dice4, dice5):
        """
        """
        if score == -1:
            score = 0
            if self.same_of_kind(5, dice1, dice2, dice3, dice4, dice5):
                score = 100

            return {
                    'name': 'yams',
                    'value': score,
                    'new': score > 0,
                    'cancel': score == 0
                    }
        else:
            return {
                    'name': 'yams',
                    'value': score,
                    'new': False,
                    'cancel': False
                    }

    def total(self, name):
        return {
                'name': name,
                'value': '',
                'new': False,
                'cancel': False
                }

    def __get_dice_value(self, dice_str, player):
        """
        """
        query = Dice().all()
        query.filter('name =', dice_str)
        query.filter('player =', player)
        dice = query.get()

        if dice:
            return dice.value

        else:
            return 0

    def get_score(self, player_key):
        """
        """
        player = Player().get(player_key)

        d1 = self.__get_dice_value('dice1', player)
        d2 = self.__get_dice_value('dice2', player)
        d3 = self.__get_dice_value('dice3', player)
        d4 = self.__get_dice_value('dice4', player)
        d5 = self.__get_dice_value('dice5', player)

        if player.score:
            return [
                    self.one(player.score.one, d1, d2, d3, d4, d5),
                    self.two(player.score.two, d1, d2, d3, d4, d5),
                    self.three(player.score.three, d1, d2, d3, d4, d5),
                    self.four(player.score.four, d1, d2, d3, d4, d5),
                    self.five(player.score.five, d1, d2, d3, d4, d5),
                    self.six(player.score.six, d1, d2, d3, d4, d5),
                    self.total('total1'),
                    self.three_of_kind(player.score.three_of_kind, d1, d2, d3, d4, d5),
                    self.four_of_kind(player.score.four_of_kind, d1, d2, d3, d4, d5),
                    self.full(player.score.full, d1, d2, d3, d4, d5),
                    self.small_suite(player.score.small_suite, d1, d2, d3, d4, d5),
                    self.big_suite(player.score.big_suite, d1, d2, d3, d4, d5),
                    self.lucky(player.score.lucky, d1, d2, d3, d4, d5),
                    self.yams(player.score.yams, d1, d2, d3, d4, d5),
                    self.total('total2'),
                    self.total('total_all'),
                    ]
        else:
            return [0, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, 0, '', '',]


    def update_score(self, player_key, score_name, score_value):
        """
        """
        player = Player().get(player_key)

        total_one = 0
        total_two = 0
        total_all = 0

        if score_name == 'one':
            player.score.one = int(score_value)
            total_one += int(score_value)
        elif player.score.one > -1:
            total_one += player.score.one


        if score_name == 'two':
            player.score.two = int(score_value)
            total_one += int(score_value)
        elif player.score.two > -1:
            total_one += player.score.two

        if score_name == 'three':
            player.score.three = int(score_value)
            total_one += int(score_value)
        elif player.score.three > -1:
            total_one += player.score.three

        if score_name == 'four':
            player.score.four = int(score_value)
            total_one += int(score_value)
        elif player.score.four > -1:
            total_one += player.score.four

        if score_name == 'five':
            player.score.five = int(score_value)
            total_one += int(score_value)
        elif player.score.five > -1:
            total_one += player.score.five

        if score_name == 'six':
            player.score.six = int(score_value)
            total_one += int(score_value)
        elif player.score.six > -1:
            total_one += player.score.six

        player.score.total_one = total_one

        if score_name == '3_of_kind':
            player.score.three_of_kind = int(score_value)
            total_two += int(score_value)
        elif player.score.three_of_kind > -1:
            total_two += player.score.three_of_kind

        if score_name == '4_of_kind':
            player.score.four_of_kind = int(score_value)
            total_two += int(score_value)
        elif player.score.four_of_kind > -1:
            total_two += player.score.four_of_kind

        if score_name == 'full':
            player.score.full = int(score_value)
            total_two += int(score_value)
        elif player.score.full > -1:
            total_two += player.score.full

        if score_name == 's_suite':
            player.score.small_suite = int(score_value)
            total_two += int(score_value)
        elif player.score.small_suite > -1:
            total_two += player.score.small_suite

        if score_name == 'b_suite':
            player.score.big_suite = int(score_value)
            total_two += int(score_value)
        elif player.score.big_suite > -1:
            total_two += player.score.big_suite

        if score_name == 'lucky':
            player.score.lucky = int(score_value)
            total_two += int(score_value)
        elif player.score.lucky > -1:
            total_two += player.score.lucky

        if score_name == 'yams':
            player.score.yams = int(score_value)
            total_two += int(score_value)
        elif player.score.yams > -1:
            total_two += player.score.yams

        player.score.total_two = total_two
        player.score.total_all = total_one + total_two

        player.score.put()
        player.put()

    def show(self, player_key, new_turn=True):
        """
        """
        player = Player().get(player_key)
        #
        query = Dice().all()
        query.filter('name =', 'dice1')
        query.filter('player =', player)
        dice1 = query.get()
        #
        query = Dice().all()
        query.filter('name =', 'dice2')
        query.filter('player =', player)
        dice2 = query.get()
        #
        query = Dice().all()
        query.filter('name =', 'dice3')
        query.filter('player =', player)
        dice3 = query.get()
        #
        query = Dice().all()
        query.filter('name =', 'dice4')
        query.filter('player =', player)
        dice4 = query.get()
        #
        query = Dice().all()
        query.filter('name =', 'dice5')
        query.filter('player =', player)
        dice5 = query.get()

        player_query = Player.all()
        player_query.filter('game =', player.game)
        player_query.order('name')

        # set the template for edit
        self.template_values['player'] = player
        self.template_values['dice1'] = dice1
        self.template_values['dice2'] = dice2
        self.template_values['dice3'] = dice3
        self.template_values['dice4'] = dice4
        self.template_values['dice5'] = dice5
        self.template_values['new_turn'] = new_turn
        self.template_values['player'] = player
        self.template_values['score'] = self.get_score(player_key)
        self.template_values['players'] = player_query

        # find the template
        path = os.path.join(os.path.dirname(__file__),
                                '../templates', 'yams', 'roll.html')

        # display the contact
        return template.render(path, self.template_values)

    def show_game(self, player_key=None, game_key=None):
        """
        """
        # init
        player = None
        # all
        player_query = Player.all()

        # filter
        if not player_key or player_key == '':
            game = Game().get(game_key)
            player_query.filter('game =', game)

        if not game_key or game_key == '':
            player = Player().get(player_key)
            player_query.filter('game =', player.game)

        # order
        player_query.order('name')

        if not player:
            player = player_query.get()

        # set the template for edit
        self.template_values['player'] = player
        self.template_values['score'] = self.get_score(player.key())
        self.template_values['players'] = player_query

        # find the template
        path = os.path.join(os.path.dirname(__file__),
                                '../templates', 'yams', 'show_game.html')

        # display the contact
        return template.render(path, self.template_values)
